home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2009 February
/
PCWFEB09.iso
/
Software
/
Linux
/
Kubuntu 8.10
/
kubuntu-8.10-desktop-i386.iso
/
casper
/
filesystem.squashfs
/
usr
/
bin
/
apport-cli
< prev
next >
Wrap
Text File
|
2008-10-24
|
10KB
|
293 lines
#!/usr/bin/python
'''Command line Apport user interface.
Copyright (C) 2007 Canonical Ltd.
Author: Michael Hofmann <mh21@piware.de>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See http://www.gnu.org/copyleft/gpl.html for
the full text of the license.
'''
# Web browser support:
# w3m, lynx: do not work
# elinks: works
import os.path, os, sys, subprocess, re, errno
import tty, termios
from datetime import datetime
try:
from gettext import gettext as _
import apport.ui
except ImportError, e:
# this can happen while upgrading python packages
print >> sys.stderr, 'Could not import module, is a package upgrade in progress? Error:', e
sys.exit(1)
class CLIDialog:
'''Command line dialog wrapper.'''
def __init__(self, heading, text):
self.heading = '\n*** ' + heading + '\n'
self.text = text
self.keys = []
self.buttons = []
self.visible = False
def raw_input_char(self, text):
""" raw_input, but read only one character """
sys.stdout.write(text + ' ')
file = sys.stdin.fileno()
saved_attributes = termios.tcgetattr(file)
attributes = termios.tcgetattr(file)
attributes[3] = attributes[3] & ~(termios.ICANON)
attributes[6][termios.VMIN] = 1
attributes[6][termios.VTIME] = 0
termios.tcsetattr(file, termios.TCSANOW, attributes)
try:
ch = str(sys.stdin.read(1))
finally:
termios.tcsetattr(file, termios.TCSANOW, saved_attributes)
print
return ch
def show(self):
self.visible = True
print self.heading
print self.text
def run(self):
if not self.visible:
self.show()
print
try:
# Only one button
if len (self.keys) <= 1:
self.raw_input_char(_('Press any key to continue...'))
return 0
# Multiple choices
while True:
print _('What would you like to do? Your options are:')
for index, button in enumerate(self.buttons):
print ' %s: %s' % (self.keys[index], button)
response = self.raw_input_char(_('Please choose (%s):') % ('/'.join(self.keys)))
try:
return self.keys.index(response[0].upper()) + 1
except ValueError:
pass
except KeyboardInterrupt:
print
sys.exit(1)
def addbutton(self, button):
self.keys.append(re.search('&(.)', button).group(1).upper())
self.buttons.append(re.sub('&', '', button))
return len(self.keys)
class CLIProgressDialog(CLIDialog):
'''Command line progress dialog wrapper.'''
def __init__(self, heading, text):
CLIDialog.__init__(self, heading, text)
self.progresscount = 0
def set(self, progress = None):
self.progresscount = (self.progresscount + 1) % 5
if self.progresscount:
return
if progress != None:
sys.stdout.write('\r%u%%' % (progress * 100))
else:
sys.stdout.write('.')
sys.stdout.flush()
class CLIUserInterface(apport.ui.UserInterface):
'''Command line Apport user interface'''
def __init__(self):
apport.ui.UserInterface.__init__(self)
#
# ui_* implementation of abstract UserInterface classes
#
def ui_present_crash(self, desktop_entry):
date = datetime.strptime(self.report['Date'], '%a %b %d %H:%M:%S %Y')
# adapt dialog heading and label appropriately
if desktop_entry:
name = desktop_entry.getName()
elif self.report.has_key('ExecutablePath'):
name = os.path.basename(self.report['ExecutablePath'])
else:
name = self.cur_package
# translators: first %s: application name, second %s: date, third %s: time
heading = _('%s closed unexpectedly on %s at %s.') % (name, date.date(), date.time())
dialog = CLIDialog(
heading,
_('If you were not doing anything confidential (entering passwords or other\n'
'private information), you can help to improve the application by reporting\n'
'the problem.'))
report = dialog.addbutton(_('&Report Problem...'))
ignore = dialog.addbutton(_('Cancel and &ignore future crashes of this program version'))
dialog.addbutton(_('&Cancel'))
# show crash notification dialog
response = dialog.run()
if response == report:
return {'action': 'report', 'blacklist': False}
if response == ignore:
return {'action': 'cancel', 'blacklist': True}
# Fallback
return {'action': 'cancel', 'blacklist': False}
def ui_present_package_error(self):
name = self.report['Package']
dialog = CLIDialog(
_('The package "%s" failed to install or upgrade.') % name,
_('You can help the developers to fix the package by reporting the problem.'))
report = dialog.addbutton(_('&Report Problem...'))
dialog.addbutton(_('&Cancel'))
response = dialog.run()
if response == report:
return 'report'
# Fallback
return 'cancel'
def ui_present_kernel_error(self):
dialog = CLIDialog (
_('The kernel encountered a serious problem'),
_('Your system might become unstable now and might need to be restarted.\n'
'You can help the developers to fix the problem by reporting it.'))
report = dialog.addbutton(_('&Report Problem...'))
dialog.addbutton(_('&Cancel'))
response = dialog.run()
if response == report:
return 'report'
# Fallback
return 'cancel'
def ui_present_report_details(self):
dialog = CLIDialog (
_('Send problem report to the developers?'),
_('After the problem report has been sent, please fill out the form in the\n'
'automatically opened web browser.'))
# report contents
details = ''
for key in self.report:
details += key + ':'
# string value
if not hasattr(self.report[key], 'gzipvalue') and \
hasattr(self.report[key], 'isspace') and \
not self.report._is_binary(self.report[key]):
lines = self.report[key].splitlines()
if len(lines) <= 1:
details += ' ' + self.report[key] + '\n'
else:
details += '\n'
for line in lines:
details += ' ' + line + '\n'
else:
details += ' ' + _('(binary data)') + '\n'
# complete/reduced reports
if self.report.has_key('CoreDump') and self.report.has_useful_stacktrace():
complete = dialog.addbutton(_('&Send complete report (recommended; %s)') %
self.format_filesize(self.get_complete_size()))
reduced = dialog.addbutton(_('Send &reduced report (slow Internet connection; %s)') %
self.format_filesize(self.get_reduced_size()))
else:
complete = dialog.addbutton(_('&Send report (%s)') %
self.format_filesize(self.get_complete_size()))
reduced = None
view = dialog.addbutton(_('&View report'))
save = dialog.addbutton(_('&Keep report file for sending later or copying to somewhere else'))
dialog.addbutton(_('&Cancel'))
while True:
response = dialog.run()
if response == complete:
return 'full'
if response == reduced:
return 'reduced'
if response == view:
try:
subprocess.Popen(["/usr/bin/sensible-pager"],
stdin=subprocess.PIPE,
close_fds=True).communicate(details)
except IOError, e:
# ignore broken pipe (premature quit)
if e.errno == errno.EPIPE:
pass
else:
raise
continue
if response == save:
print _('Problem report file:'), self.report_file
return 'cancel'
# Fallback
return 'cancel'
def ui_info_message(self, title, text):
dialog = CLIDialog(title, text)
dialog.addbutton(_('&Confirm'))
dialog.run()
def ui_error_message(self, title, text):
dialog = CLIDialog(_('Error: %s') % title, text)
dialog.addbutton(_('&Confirm'))
dialog.run()
def ui_start_info_collection_progress(self):
self.progress = CLIProgressDialog (
_('Collecting problem information'),
_('The collected information can be sent to the developers to improve the\n'
'application. This might take a few minutes.'))
self.progress.show()
def ui_pulse_info_collection_progress(self):
self.progress.set()
def ui_stop_info_collection_progress(self):
print
def ui_start_upload_progress(self):
self.progress = CLIProgressDialog (
_('Uploading problem information'),
_('The collected information is being sent to the bug tracking system.\n'
'This might take a few minutes.'))
self.progress.show()
def ui_set_upload_progress(self, progress):
self.progress.set(progress)
def ui_stop_upload_progress(self):
print
if __name__ == '__main__':
app = CLIUserInterface()
if not app.run_argv():
print >> sys.stderr, _('No pending crash reports. Try --help for more information.')